package edu.cmu.cs.cs214.hw9.client.controllers.eventhandlers;

import java.awt.Container;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.SwingWorker;

import edu.cmu.cs.cs214.hw9.client.controllers.BackendCacheAdapter;
import edu.cmu.cs.cs214.hw9.client.controllers.SessionController;
import edu.cmu.cs.cs214.hw9.client.gui.ProfileScreen;
import edu.cmu.cs.cs214.hw9.datatypes.Status;
import edu.cmu.cs.cs214.hw9.datatypes.User;

/**
 * Searches the database for a person.
 */
public class SearchHandler extends SessionEventHandler {
	// Quick inner class for convenience. Stores the search result.
	private class SearchResult {
		public User user;
		public boolean isFriend;
		public List<Status> statusList;
	}
	
	/**
	 * Perform the search in a separate thread from the swing thread to prevent
	 * the GUI from freezing while the search is being conducted. 
	 */
	private class SearchWorker extends SwingWorker<SearchResult, Void> {
		private BackendCacheAdapter model;
		private Container contentPane;
		private User currentUser;
		private String searchString;
		
		/**
		 * Creates a search request based on the provided search string.
		 * 
		 * @param searchString String to search.
		 */
		public SearchWorker(String searchString) {
			this.searchString = searchString;
			currentUser = controller.getCurrentUser();
			model = controller.getModel();
			contentPane = controller.getFrame();
		}
		
		/**
		 * Search for a user by comparing the provided string with their name,
		 * using a linear search.
		 * 
		 * @return NULL if no such user; the found user data, in a User object, otherwise.
		 */
		public SearchResult doInBackground() {
			List<User> userList = model.getUsers();
			
			for (User u : userList) {
				if (u.getFullname().toLowerCase().contains(searchString)) {
					SearchResult result = new SearchResult();
					
					result.user = u;
					result.isFriend = model.areFriends(currentUser, u);
					
					List<Status> statusList = model.getStatuses(u);
					if (statusList.size() > 5) statusList = statusList.subList(0, 5);
					result.statusList = statusList;
					
					return result;
				}
			}

			return null;
		}
		
		/**
		 * Shows the user the profile of the user that is found, or notify him that
		 * no such user is found.
		 */
		public void done() {
			try {
				SearchResult result = get();
				if (result == null) JOptionPane.showMessageDialog(contentPane, "Unable to find " + searchString); 
				else changeScreen(new ProfileScreen(currentUser, result.user, result.statusList, result.isFriend));
			} catch (Exception e) {
				throw new RuntimeException("Fatal error occured during search: " + e.getMessage());
			}
		}
	};
	
	/**
	 * Set the current session controller to the provided controller.
	 * 
	 * @param controller Controller to associate with this event handler.
	 */
	public SearchHandler(SessionController controller) { super(controller); }
	
	/**
	 * Create the search request and run it in an outside thread.
	 * 
	 * @param param String/name to search for.
	 */
	public void handleEvent(Object param) {
		SearchWorker searchWorker = new SearchWorker((String) param);
		searchWorker.execute();
	}

}
